local Element = import("./Element.lua");


local ListBox = commonlib.inherit(Element);

ListBox:Property("Select");
ListBox:Property("HoverIndex", 0);

function ListBox:OnAfterUpdateChildrenLayout()
    local width, height = self:GetLayout():GetWidthHeight();
    local options = self:GetSelect():GetOptions();
    local line_height = self:GetLineHeight();
    self:GetLayout():SetRealContentWidthHeight(width, (#options) * line_height);
end

function ListBox:RenderContent()
    -- 绘制下拉列表
    local options = self:GetSelect():GetOptions();
    local x, y, w, h = self:GetPosition();
    local _, realContentHeight = self:GetRealContentWidthHeight();
    local line_height = self:GetLineHeight();
    local height = math.min(realContentHeight, h);
    local is_overflow = realContentHeight > h;
    local opt_x, opt_y = self:GetContentPosition();
    self:SetPenColor(0xcc, 0xcc, 0xcc, 0xff);
    self:DrawRectangle(x, y, w, height, false, true);
    self:SetFont(self.__style_font_weight__, self.__style_font_slant__, self.__style_font_family__);
    self:SetFontSize(self.__style_font_size__);
    self:SetFontColor(self.__style_color__.r, self.__style_color__.g, self.__style_color__.b, self.__style_color__.a);
    if (is_overflow) then
        self:Save();
        self:DrawRectangle(x, opt_y, w, height, false, false);
        self:Clip();
        self:Translate(-self.__scroll_x__, -self.__scroll_y__);
    end
    local hoverIndex = self:GetHoverIndex();
    for index, option in ipairs(options) do
        if (hoverIndex == index) then
            self:SetBrushColor(0xcc, 0xcc, 0xcc, 0xff); -- 悬浮项背景色
            self:DrawRectangle(x, opt_y, w, line_height);
        end
        self:DrawText(opt_x, opt_y, w, line_height, option[1]);
        opt_y = opt_y + line_height;
    end
    if (is_overflow) then
        self:Translate(self.__scroll_x__, self.__scroll_y__);
        self:Restore();
    end
end

function ListBox:GetOptionIndex(event)
    local options = self:GetSelect():GetOptions();
    local max_index = #options;
    local scrollX, scrollY = self:GetScrollXY();
    local x, y = event:GetXY();
    local relx, rely = self:ScreenXYToElementXY(x, y);
    local line_height = self:GetLineHeight();
    return math.max(1, math.min(max_index, math.ceil((rely + scrollY) / line_height)));
end

function ListBox:OnMouseMove(event)
    self:SetHoverIndex(self:GetOptionIndex(event));
end

function ListBox:OnMouseWheel(event)
    ListBox._super.OnMouseWheel(self, event);
    self:SetHoverIndex(self:GetOptionIndex(event));
end

function ListBox:OnMouseDown(event)
    self:CaptureMouse();
end

function ListBox:OnMouseUp(event)
    self:ReleaseMouse();
    self:GetSelect():OnSelect(self:GetOptionIndex(event));
    self:Hide();
end

local Select = commonlib.inherit(Element);

Select:Property("Options");
Select:Property("Value");
Select:Property("Label");
Select:Property("ListBox");
Select:Property("SelectIndex", 0);
Select:Property("DefaultStyle", "box-sizing: border-box; display: inline-block; border-width: 1px; border-color: #cccccc; color: #000000; height: 30px; line-height: 30px; width: 120px; padding-left: 4px; padding-right: 30px; background-color: #ffffff;");

function Select:ctor()
    self:SetName("Select");
end

function Select:Init(xmlnode, window, parent)
    Select._super.InitElement(self, xmlnode, window, parent);

    local listbox = ListBox:new():Init({
        name = "select-list-box",
        attr = {
            style = "box-sizing: border-box; position: absolute; top: 100%; left: 0px; width: 100%; height: 150px; overflow-y: auto; padding-left: 4px;"
        }
    }, window, self);

    listbox:SetSelect(self);
    listbox:Hide();

    self:AddChildren(listbox);
    self:SetListBox(listbox);

    self:OnAttrValueChange("options");
    self:OnAttrValueChange("value");
    return self;
end

function Select:OnAttrValueChange(attrName)
    if (attrName == "options") then
        local attr_options = self:GetAttrTableValue("options");
        local options = {};
        for _, option in ipairs(attr_options) do
            if (type(option) == "string") then 
                table.insert(options, {option, option}); 
            elseif (type(option) == "table") then
                table.insert(options, {option[1] or option.label, option[2] or option.value});
            end
        end
        self:SetOptions(options);
    elseif (attrName == "value") then
        self:SetValue(self:GetAttrStringValue("value"));
        self:SetLabel(self:GetLabelByValue(self:GetValue()));
    end
end

function Select:GetLabelByValue(value)
    for _, option in ipairs(self:GetOptions()) do
        if (option[2] == value) then return option[1] end 
    end
    return value;
end

function Select:GetValueByLabel(label)
    for _, option in ipairs(self:GetOptions()) do
        if (option[1] == label) then return option[2] end
    end
    return label;
end

function Select:IsShowArrowIcon()
    return self:GetAttrBoolValue("isShowArrowIcon", true);
end

function Select:OnChange(value, label)
    label = label or self:GetLabelByValue(value);
    self:SetValue(value);
    self:SetLabel(label);
    self:CallAttrFunction("onchange", nil, value, label);
end

function Select:OnSelect(opt_index)
    opt_index = opt_index or 0;
    local options = self:GetOptions();
    local size = #options;
    if (opt_index < 1 or opt_index > size or opt_index == self:GetSelectIndex()) then return end 
    self:SetSelectIndex(opt_index);
    local option = options[opt_index];
    self:OnChange(option[2], option[1]);
end

function Select:OnMouseDown(event)
    self:CaptureMouse();
    self:GetListBox():Show();
end

function Select:OnMouseUp(event)
    self:ReleaseMouse();
end

function Select:RenderContent()
    local x, y, w, h = self:GetContentPosition();

    self:SetFont(self.__style_font_weight__, self.__style_font_slant__, self.__style_font_family__);
    self:SetFontSize(self.__style_font_size__);
    self:SetFontColor(self.__style_color__.r, self.__style_color__.g, self.__style_color__.b, self.__style_color__.a);
    self:DrawText(x, y, w, h, self:GetLabel());

    if (self:IsShowArrowIcon()) then
        x, y, w, h = self:GetPosition();
        local arrow_offset_x = 8;
        local arrow_offset_y = 8;
        local arrow_size = h - 2 * arrow_offset_y;
        local is_show_listbox = self:GetListBox():IsExist();
        self:SetBrushColor(0xcc, 0xcc, 0xcc, 0xff);
        -- self:DrawTriangle(x + w - arrow_offset_x - arrow_size, y + arrow_offset_y,  x + w - arrow_offset_x, y + arrow_offset_y, x + w - arrow_offset_x - arrow_size / 2, y + h - arrow_offset_y);
        if (not is_show_listbox) then  -- 倒三角
            self:DrawTriangle(x + w - arrow_offset_x - arrow_size, y + arrow_offset_y,  x + w - arrow_offset_x, y + arrow_offset_y, x + w - arrow_offset_x - arrow_size / 2, y + h - arrow_offset_y);
        else                       -- 正三角
            self:DrawTriangle(x + w - arrow_offset_x - arrow_size, y + h - arrow_offset_y,  x + w - arrow_offset_x, y + h - arrow_offset_y, x + w - arrow_offset_x - arrow_size / 2, y + arrow_offset_y);
        end
    end
end

return Select;